using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    /// <summary>
    /// 通知仓储实现
    /// </summary>
    public class NotificationRepository : Repository<Notification>, INotificationRepository
    {
        public NotificationRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Notification>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(n => n.UserId == userId).OrderByDescending(n => n.CreatedAt).ToListAsync();
        }

        public async Task<IEnumerable<Notification>> GetUnreadNotificationsAsync(Guid userId)
        {
            return await _dbSet
                .Where(n => n.UserId == userId && !n.IsRead)
                .OrderByDescending(n => n.CreatedAt)
                .ToListAsync();
        }

        public async Task<IEnumerable<Notification>> GetByTypeAsync(Guid userId, string type)
        {
            return await _dbSet
                .Where(n => n.UserId == userId && n.Type == type)
                .OrderByDescending(n => n.CreatedAt)
                .ToListAsync();
        }

        public async Task<int> GetUnreadCountAsync(Guid userId)
        {
            return await _dbSet.CountAsync(n => n.UserId == userId && !n.IsRead);
        }

        public async Task<Dictionary<string, int>> GetNotificationCountByTypeAsync(Guid userId)
        {
            var notifications = await _dbSet
                .Where(n => n.UserId == userId)
                .GroupBy(n => n.Type)
                .Select(n => new { Type = n.Key, Count = n.Count() })
                .ToListAsync();

            return notifications.ToDictionary(n => n.Type, n => n.Count);
        }

        public async Task<Dictionary<string, int>> GetUnreadNotificationCountByTypeAsync(Guid userId)
        {
            var notifications = await _dbSet
                .Where(n => n.UserId == userId && !n.IsRead)
                .GroupBy(n => n.Type)
                .Select(n => new { Type = n.Key, Count = n.Count() })
                .ToListAsync();

            return notifications.ToDictionary(n => n.Type, n => n.Count);
        }

        public async Task MarkAsReadAsync(Guid notificationId)
        {
            var notification = await _dbSet.FindAsync(notificationId);
            if (notification != null && !notification.IsRead)
            {
                notification.IsRead = true;
                notification.ReadAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
            }
        }

        public async Task MarkAllAsReadAsync(Guid userId)
        {
            var notifications = await _dbSet
                .Where(n => n.UserId == userId && !n.IsRead)
                .ToListAsync();

            foreach (var notification in notifications)
            {
                notification.IsRead = true;
                notification.ReadAt = DateTime.UtcNow;
            }

            await _context.SaveChangesAsync();
        }
    }

    /// <summary>
    /// 提醒仓储实现
    /// </summary>
    public class ReminderRepository : Repository<Reminder>, IReminderRepository
    {
        public ReminderRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<Reminder>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(r => r.UserId == userId).OrderBy(r => r.RemindTime).ToListAsync();
        }

        public async Task<IEnumerable<Reminder>> GetActiveRemindersAsync(Guid userId)
        {
            var now = DateTime.UtcNow;
            return await _dbSet
                .Where(r => r.UserId == userId && r.IsActive && r.RemindTime > now)
                .OrderBy(r => r.RemindTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<Reminder>> GetOverdueRemindersAsync(Guid userId)
        {
            var now = DateTime.UtcNow;
            return await _dbSet
                .Where(r => r.UserId == userId && r.IsActive && r.RemindTime <= now)
                .OrderBy(r => r.RemindTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<Reminder>> GetByTypeAsync(Guid userId, string type)
        {
            return await _dbSet
                .Where(r => r.UserId == userId && r.Type == type)
                .OrderBy(r => r.RemindTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<Reminder>> GetByDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(r => r.UserId == userId && r.RemindTime >= startDate && r.RemindTime <= endDate)
                .OrderBy(r => r.RemindTime)
                .ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetReminderCountByTypeAsync(Guid userId)
        {
            var reminders = await _dbSet
                .Where(r => r.UserId == userId)
                .GroupBy(r => r.Type)
                .Select(r => new { Type = r.Key, Count = r.Count() })
                .ToListAsync();

            return reminders.ToDictionary(r => r.Type, r => r.Count);
        }

        public async Task<Dictionary<string, int>> GetActiveReminderCountByTypeAsync(Guid userId)
        {
            var now = DateTime.UtcNow;
            var reminders = await _dbSet
                .Where(r => r.UserId == userId && r.IsActive && r.RemindTime > now)
                .GroupBy(r => r.Type)
                .Select(r => new { Type = r.Key, Count = r.Count() })
                .ToListAsync();

            return reminders.ToDictionary(r => r.Type, r => r.Count);
        }

        public async Task MarkAsCompletedAsync(Guid reminderId)
        {
            var reminder = await _dbSet.FindAsync(reminderId);
            if (reminder != null)
            {
                reminder.IsActive = false;
                reminder.CompletedAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
            }
        }

        public async Task SnoozeReminderAsync(Guid reminderId, DateTime newRemindTime)
        {
            var reminder = await _dbSet.FindAsync(reminderId);
            if (reminder != null)
            {
                reminder.RemindTime = newRemindTime;
                reminder.SnoozeCount++;
                await _context.SaveChangesAsync();
            }
        }
    }

    /// <summary>
    /// 提醒历史仓储实现
    /// </summary>
    public class ReminderHistoryRepository : Repository<ReminderHistory>, IReminderHistoryRepository
    {
        public ReminderHistoryRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<ReminderHistory>> GetByReminderIdAsync(Guid reminderId)
        {
            return await _dbSet.Where(h => h.ReminderId == reminderId).OrderByDescending(h => h.TriggeredAt).ToListAsync();
        }

        public async Task<IEnumerable<ReminderHistory>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(h => h.UserId == userId).OrderByDescending(h => h.TriggeredAt).ToListAsync();
        }

        public async Task<IEnumerable<ReminderHistory>> GetByDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(h => h.UserId == userId && h.TriggeredAt >= startDate && h.TriggeredAt <= endDate)
                .OrderByDescending(h => h.TriggeredAt)
                .ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetTriggerCountByTypeAsync(Guid userId)
        {
            var histories = await _dbSet
                .Where(h => h.UserId == userId)
                .GroupBy(h => h.Type)
                .Select(h => new { Type = h.Key, Count = h.Count() })
                .ToListAsync();

            return histories.ToDictionary(h => h.Type, h => h.Count);
        }

        public async Task<Dictionary<string, int>> GetActionCountByTypeAsync(Guid userId)
        {
            var histories = await _dbSet
                .Where(h => h.UserId == userId)
                .GroupBy(h => h.Action)
                .Select(h => new { Action = h.Key, Count = h.Count() })
                .ToListAsync();

            return histories.ToDictionary(h => h.Action, h => h.Count);
        }
    }

    /// <summary>
    /// 用户通知设置仓储实现
    /// </summary>
    public class UserNotificationSettingRepository : Repository<UserNotificationSetting>, IUserNotificationSettingRepository
    {
        public UserNotificationSettingRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<UserNotificationSetting?> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.FirstOrDefaultAsync(s => s.UserId == userId);
        }

        public async Task<Dictionary<string, bool>> GetNotificationSettingsByUserIdAsync(Guid userId)
        {
            var settings = await _dbSet.FirstOrDefaultAsync(s => s.UserId == userId);
            if (settings == null)
            {
                return new Dictionary<string, bool>();
            }

            return new Dictionary<string, bool>
            {
                { "EmailEnabled", settings.EmailEnabled },
                { "SmsEnabled", settings.SmsEnabled },
                { "PushEnabled", settings.PushEnabled },
                { "InAppEnabled", settings.InAppEnabled },
                { "MenstrualReminderEnabled", settings.MenstrualReminderEnabled },
                { "SkincareReminderEnabled", settings.SkincareReminderEnabled },
                { "MealReminderEnabled", settings.MealReminderEnabled },
                { "WaterReminderEnabled", settings.WaterReminderEnabled },
                { "ExerciseReminderEnabled", settings.ExerciseReminderEnabled },
                { "SocialNotificationEnabled", settings.SocialNotificationEnabled },
                { "SystemNotificationEnabled", settings.SystemNotificationEnabled }
            };
        }

        public async Task UpdateNotificationSettingsAsync(Guid userId, Dictionary<string, bool> settings)
        {
            var userSettings = await _dbSet.FirstOrDefaultAsync(s => s.UserId == userId);
            if (userSettings == null)
            {
                userSettings = new UserNotificationSetting { UserId = userId };
                _dbSet.Add(userSettings);
            }

            if (settings.ContainsKey("EmailEnabled"))
                userSettings.EmailEnabled = settings["EmailEnabled"];

            if (settings.ContainsKey("SmsEnabled"))
                userSettings.SmsEnabled = settings["SmsEnabled"];

            if (settings.ContainsKey("PushEnabled"))
                userSettings.PushEnabled = settings["PushEnabled"];

            if (settings.ContainsKey("InAppEnabled"))
                userSettings.InAppEnabled = settings["InAppEnabled"];

            if (settings.ContainsKey("MenstrualReminderEnabled"))
                userSettings.MenstrualReminderEnabled = settings["MenstrualReminderEnabled"];

            if (settings.ContainsKey("SkincareReminderEnabled"))
                userSettings.SkincareReminderEnabled = settings["SkincareReminderEnabled"];

            if (settings.ContainsKey("MealReminderEnabled"))
                userSettings.MealReminderEnabled = settings["MealReminderEnabled"];

            if (settings.ContainsKey("WaterReminderEnabled"))
                userSettings.WaterReminderEnabled = settings["WaterReminderEnabled"];

            if (settings.ContainsKey("ExerciseReminderEnabled"))
                userSettings.ExerciseReminderEnabled = settings["ExerciseReminderEnabled"];

            if (settings.ContainsKey("SocialNotificationEnabled"))
                userSettings.SocialNotificationEnabled = settings["SocialNotificationEnabled"];

            if (settings.ContainsKey("SystemNotificationEnabled"))
                userSettings.SystemNotificationEnabled = settings["SystemNotificationEnabled"];

            userSettings.UpdatedAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();
        }
    }

    /// <summary>
    /// 消息模板仓储实现
    /// </summary>
    public class MessageTemplateRepository : Repository<MessageTemplate>, IMessageTemplateRepository
    {
        public MessageTemplateRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<MessageTemplate?> GetByCodeAsync(string code)
        {
            return await _dbSet.FirstOrDefaultAsync(t => t.Code == code);
        }

        public async Task<IEnumerable<MessageTemplate>> GetByTypeAsync(string type)
        {
            return await _dbSet.Where(t => t.Type == type).OrderBy(t => t.Name).ToListAsync();
        }

        public async Task<IEnumerable<MessageTemplate>> GetActiveTemplatesAsync()
        {
            return await _dbSet.Where(t => t.IsActive).OrderBy(t => t.Name).ToListAsync();
        }

        public async Task<Dictionary<string, string>> GetTemplateContentByCodesAsync(IEnumerable<string> codes)
        {
            var templates = await _dbSet
                .Where(t => codes.Contains(t.Code))
                .ToListAsync();

            return templates.ToDictionary(t => t.Code, t => t.Content);
        }

        public async Task<Dictionary<string, int>> GetTemplateCountByTypeAsync()
        {
            var templates = await _dbSet
                .GroupBy(t => t.Type)
                .Select(t => new { Type = t.Key, Count = t.Count() })
                .ToListAsync();

            return templates.ToDictionary(t => t.Type, t => t.Count);
        }
    }

    /// <summary>
    /// 消息发送记录仓储实现
    /// </summary>
    public class MessageSendLogRepository : Repository<MessageSendLog>, IMessageSendLogRepository
    {
        public MessageSendLogRepository(SheLifeDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<MessageSendLog>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet.Where(l => l.UserId == userId).OrderByDescending(l => l.SentAt).ToListAsync();
        }

        public async Task<IEnumerable<MessageSendLog>> GetByTemplateIdAsync(Guid templateId)
        {
            return await _dbSet.Where(l => l.TemplateId == templateId).OrderByDescending(l => l.SentAt).ToListAsync();
        }

        public async Task<IEnumerable<MessageSendLog>> GetByChannelAsync(string channel)
        {
            return await _dbSet.Where(l => l.Channel == channel).OrderByDescending(l => l.SentAt).ToListAsync();
        }

        public async Task<IEnumerable<MessageSendLog>> GetByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(l => l.SentAt >= startDate && l.SentAt <= endDate)
                .OrderByDescending(l => l.SentAt)
                .ToListAsync();
        }

        public async Task<Dictionary<string, int>> GetSendCountByChannelAsync()
        {
            var logs = await _dbSet
                .GroupBy(l => l.Channel)
                .Select(l => new { Channel = l.Key, Count = l.Count() })
                .ToListAsync();

            return logs.ToDictionary(l => l.Channel, l => l.Count);
        }

        public async Task<Dictionary<string, int>> GetSendCountByTemplateAsync()
        {
            var logs = await _dbSet
                .GroupBy(l => l.TemplateCode)
                .Select(l => new { TemplateCode = l.Key, Count = l.Count() })
                .ToListAsync();

            return logs.ToDictionary(l => l.TemplateCode, l => l.Count);
        }

        public async Task<Dictionary<string, int>> GetSendCountByStatusAsync()
        {
            var logs = await _dbSet
                .GroupBy(l => l.Status)
                .Select(l => new { Status = l.Key, Count = l.Count() })
                .ToListAsync();

            return logs.ToDictionary(l => l.Status, l => l.Count);
        }

        public async Task<Dictionary<string, double>> GetSuccessRateByChannelAsync()
        {
            var logs = await _dbSet.ToListAsync();
            var result = new Dictionary<string, double>();

            var channelGroups = logs.GroupBy(l => l.Channel);
            foreach (var group in channelGroups)
            {
                var total = group.Count();
                var success = group.Count(l => l.Status == "success");
                var rate = total > 0 ? (double)success / total * 100 : 0;
                result[group.Key] = Math.Round(rate, 2);
            }

            return result;
        }
    }
}